package model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ar.edu.unq.tpi.pconc.Channel;

public class Mapa {

	private static Map<String, Set<String>> ciudades = new HashMap<String, Set<String>>();;
	private static final Channel<String> uiSend = new Channel<String>(1);
	private static final Channel<String> uiReceive = new Channel<String>(2);
	private static final Map<Integer, Ciudad> ciudadesEnElMapa = new HashMap<Integer, Ciudad>();
	private static boolean huboGanador = false;

	/**
	 * Copiado desde ConcurBattles.parsePath por que no lo podia utilizar (Y
	 * encontre posible bug).
	 * 
	 * @param conf
	 * @return
	 */
	public static Map<String, Set<String>> parsePaths(String conf) {
		Map<String, Set<String>> result = new HashMap<String, Set<String>>();
		String[] lines = conf.split("\n");
		for (String line : lines) {
			String[] words = line.split(" ");
			if (words.length == 0)
				continue;
			Set<String> set = new HashSet<String>();
			result.put(words[1], set);
			for (int i = 2; i < words.length; ++i)
				set.add(words[i]);
		}
		return result;
	}

	public static boolean isHuboGanador() {
		return huboGanador;
	}

	public static void setHuboGanador(boolean huboGanador) {
		Mapa.huboGanador = huboGanador;
	}

	public static void posicionarUnidad(Unidad unaUnidad, Ciudad unaCiudad) {
		String mensaje = unaUnidad.getIdParaUI() + " " + unaCiudad.getNumeroDeCiudad();
		System.out.println("[Mapa] [UI] > " + mensaje);
		uiSend.send(mensaje);
	}
	
	public static Map<Integer, Ciudad> getCiudadesEnElMapa(){
		return ciudadesEnElMapa;
	}
	
	
	public static void quitarUnidad(Unidad unaUnidad) {
		String mensaje = unaUnidad.getIdParaUI();
		System.out.println("[Mapa] [UI] > " + mensaje);
		uiSend.send(mensaje);
	}
	
	public static List<Ciudad> buscarCiudadesConectadas(int ciudadActual){
		List<Ciudad> lstCity =  new ArrayList<Ciudad>();
		// TODO: Volver todo string... o volver todo int!... tenemos el mismo indice en dos tipos diferentes.
		for (String ciudad : Mapa.getCiudades().get(String.valueOf(ciudadActual))) {
			//System.out.println("[MAPA] > La ciudad " + ciudadActual + " esta conectada con la ciudad " + ciudad);
			//System.out.println(Mapa.ciudadesEnElMapa.get(Integer.valueOf(ciudad)));
			lstCity.add(Mapa.ciudadesEnElMapa.get(Integer.valueOf(ciudad)));
		}
		return lstCity;
	}

	public static void crearMundo() {

		System.out.println("[Mapa] > A la espera del inicio de la UI y selección de mapa.");
		String conf = uiReceive.receive();
		Mapa.setCiudades(Mapa.parsePaths(conf));
		// System.out.println(contenido);
		//System.out.println("Ciudades conectadas con 1:" + Mapa.getCiudades().get("1"));
		System.out.println("[Mapa] > Mapa recibido");
		Ciudad ciudadDorada = null;
		Ciudad ciudadPlateada = null;
		System.out.println("[Mapa] > Cantidad de ciudades: " + Mapa.getCiudades().size());
		for (int i = 1; i <= Mapa.getCiudades().size(); i++) {
			
			Ciudad unaCiudad = new Ciudad(i);
			Mapa.ciudadesEnElMapa.put(i, unaCiudad);
			
			if (i == 2) {
				System.out.println("[Mapa] > La ciudad dorada es: " + unaCiudad);
				ciudadDorada = unaCiudad;
			}
			if (i == Mapa.getCiudades().size()) {
				System.out.println("[Mapa] > La ciudad plateada es: " + unaCiudad);
				ciudadPlateada = unaCiudad;
			}
			
			System.out.println("[Mapa] > Creando ciudad:" + unaCiudad);
		}
		// Ahora que las ciudades estan creadas itero para llenarlas con otras ciudades.
		// Probablemente halla un algoritmo mas feliz.
		
		(new Castillo("gold", ciudadDorada)).start();
		(new Castillo("plate", ciudadPlateada)).start();
		for (int i = 1; i <= Mapa.getCiudades().size(); i++) {
			Ciudad unaCiudad = Mapa.ciudadesEnElMapa.get(i);
			unaCiudad.setCiudadesConectadas(Mapa.buscarCiudadesConectadas(i));
			unaCiudad.start();
		}
	}

	public static Map<String, Set<String>> getCiudades() {
		return ciudades;
	}

	public static void setCiudades(Map<String, Set<String>> ciudades) {
		Mapa.ciudades = ciudades;
	}

	public static boolean gameOver() {
		return huboGanador;
	}

}
